<!DOCTYPE html>
<html>
<head>
<title>React基础</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css">
html,
body,
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote,
ol,
ul,
li,
img {
    margin: 0;
    padding: 0;
    font-size: 100%;
    font: inherit;
    vertical-align: baseline;
}

html * {
    font-family: "ff-din-web-pro-1", "ff-din-web-pro-2", sans-serif;
    font-size: 16px;
    line-height: 19.2px;
    color-profile: sRGB;
}

body {
    min-width: 32em;
    max-width: 56em;
    margin: 10px auto;
}

p, blockquote p {
    line-height: 1.6;
}

ul li, ol li {
    line-height: 1.6;
}

p {
    font-weight: lighter;
    margin: 10px 0;
}

strong {
    font-weight: bold;
}

ol,
ul {
    margin-left: 2em;
}

ul ul,
ol ol,
ul ol,
ol ul {
    margin-top: 10px;
}

h1,
h2,
h3,
h4,
h5,
h6 {
    font-weight: lighter;
    text-transform: capitalize;
    margin: 20px 0;
    border-bottom: 1px solid;
    padding-bottom: 6px;
}

h1, h1 > code {
    font-size: 24.624px;
    line-height: 29.548799999999996px;
}

h2, h2 > code {
    font-size: 24.624px;
    line-height: 29.548799999999996px;
}

h3, h3 > code {
    font-size: 23.44px;
    line-height: 28.128px;
}

h4, h4 > code {
    font-size: 22.16px;
    line-height: 26.592px;
}

h5, h5 > code {
    font-size: 22.16px;
    line-height: 26.592px;
}

h6, h6 > code {
    font-size: 22.16px;
    line-height: 26.592px;
}

img {
    margin-bottom: 20px;
}

h1 img,
h2 img,
h3 img,
h4 img,
h5 img,
h6 img,
p img {
    margin-bottom: 0;
}

pre,
code {
    font-family: monospace, Consolas, "Source Code Pro", Arial, sans-serif;
    color: #586e75;
    background-color: #eee8d5;
}

pre {
    white-space: pre-wrap;
    word-wrap: break-word;
    padding: 12px 20px;
    margin-bottom: 20px;
}

code {
    border-radius: 3px;
}

h1 {
    text-transform: uppercase;
    font-weight: bold;
}

h3,
h4,
h5,
h6 {
    border-bottom: none;
}

html * {
    color: #657b83;
}

html body {
    background-color: #fdf6e3;
}

html h1,
html h2,
html h3,
html h4,
html h5,
html h6 {
    color: #586e75;
    border-color: #657b83;
}

html a,
html a:active,
html a:visited {
    color: #586e75;
    text-decoration: none;
    border-bottom: 1px dashed;
    padding-bottom: 2px;
    border-radius: 2px;
}

html a:hover {
    background-color: #eee8d5;
}

blockquote a:hover {
    background-color: #fdf6e3;
}

html a,
html a:active,
html a:visited,
html code.url {
    color: #b58900;
}

html h1 {
    color: #b58900;
}

html h2,
html h3,
html h4,
html h5,
html h6 {
    color: #b58900;
}

/* QUOTES
=============================================================================*/
blockquote {
    border-left: 4px solid #b58900;
    padding: 12px 20px;
    background: #eee8d5;
    border-bottom-right-radius: 2px;
}

blockquote code {
    background: #fdf6e3;
}

blockquote > :first-child {
    margin-top: 0;
}

blockquote > :last-child {
    margin-bottom: 0;
}

/* TABLES
=============================================================================*/
table {
    margin: 0 auto;
    border-collapse: collapse;
    width: 100%;
    box-sizing: border-box;
    margin-bottom: 30px;
}

table th, table td {
    border: 1px solid #ccc;
    padding: 6px 13px;
}

table td {
    word-break: break-word;
    line-height: 1.3;
}

table th {
    font-weight: bold;
    text-align: center !important;
    background-color: #eee8d5;
}

table tr {
    border-top: 1px solid #ccc;
    background-color: #fdf6e3;
}

/* IMAGES
=============================================================================*/
img {
    max-width: 100%;
}

p > img {
    display: table;
    margin: 0 auto;
}

p code, li code, td code {
    padding: 1px 3px;
    border-radius: 3px;
}

.cp_embed_wrapper {
    margin: 20px 0;
}

@media screen and (min-width: 980px) and (max-width: 980px) {
    table thead tr th,
    table thead tr th > code,
    table tbody tr td,
    table tbody tr td > code,
    table tbody tr td > strong {
        font-size: 1.3em;
        line-height: 1.3;
    }

    p, p code,
    p strong, p strong > code,
    blockquote p {
        font-size: 1.2em;
        line-height: 1.6;
    }

    pre > code {
        font-size: 1.2em;
        line-height: 1.2;
    }

    ol, ul {
        margin-left: 3em;
    }

    ol li, ul li {
        line-height: 1.6;
    }
}
</style>
<style type="text/css">
.highlight  { background: #ffffff; }
.highlight .c { color: #999988; font-style: italic } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { font-weight: bold } /* Keyword */
.highlight .o { font-weight: bold } /* Operator */
.highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */
.highlight .cp { color: #999999; font-weight: bold } /* Comment.Preproc */
.highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */
.highlight .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .gd .x { color: #000000; background-color: #ffaaaa } /* Generic.Deleted.Specific */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #999999 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .gi .x { color: #000000; background-color: #aaffaa } /* Generic.Inserted.Specific */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #aaaaaa } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { font-weight: bold } /* Keyword.Constant */
.highlight .kd { font-weight: bold } /* Keyword.Declaration */
.highlight .kp { font-weight: bold } /* Keyword.Pseudo */
.highlight .kr { font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #445588; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #009999 } /* Literal.Number */
.highlight .s { color: #d14 } /* Literal.String */
.highlight .na { color: #008080 } /* Name.Attribute */
.highlight .nb { color: #0086B3 } /* Name.Builtin */
.highlight .nc { color: #445588; font-weight: bold } /* Name.Class */
.highlight .no { color: #008080 } /* Name.Constant */
.highlight .ni { color: #800080 } /* Name.Entity */
.highlight .ne { color: #990000; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #990000; font-weight: bold } /* Name.Function */
.highlight .nn { color: #555555 } /* Name.Namespace */
.highlight .nt { color: #000080 } /* Name.Tag */
.highlight .nv { color: #008080 } /* Name.Variable */
.highlight .ow { font-weight: bold } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mf { color: #009999 } /* Literal.Number.Float */
.highlight .mh { color: #009999 } /* Literal.Number.Hex */
.highlight .mi { color: #009999 } /* Literal.Number.Integer */
.highlight .mo { color: #009999 } /* Literal.Number.Oct */
.highlight .sb { color: #d14 } /* Literal.String.Backtick */
.highlight .sc { color: #d14 } /* Literal.String.Char */
.highlight .sd { color: #d14 } /* Literal.String.Doc */
.highlight .s2 { color: #d14 } /* Literal.String.Double */
.highlight .se { color: #d14 } /* Literal.String.Escape */
.highlight .sh { color: #d14 } /* Literal.String.Heredoc */
.highlight .si { color: #d14 } /* Literal.String.Interpol */
.highlight .sx { color: #d14 } /* Literal.String.Other */
.highlight .sr { color: #009926 } /* Literal.String.Regex */
.highlight .s1 { color: #d14 } /* Literal.String.Single */
.highlight .ss { color: #990073 } /* Literal.String.Symbol */
.highlight .bp { color: #999999 } /* Name.Builtin.Pseudo */
.highlight .vc { color: #008080 } /* Name.Variable.Class */
.highlight .vg { color: #008080 } /* Name.Variable.Global */
.highlight .vi { color: #008080 } /* Name.Variable.Instance */
.highlight .il { color: #009999 } /* Literal.Number.Integer.Long */
.pl-c {
    color: #969896;
}

.pl-c1,.pl-mdh,.pl-mm,.pl-mp,.pl-mr,.pl-s1 .pl-v,.pl-s3,.pl-sc,.pl-sv {
    color: #0086b3;
}

.pl-e,.pl-en {
    color: #795da3;
}

.pl-s1 .pl-s2,.pl-smi,.pl-smp,.pl-stj,.pl-vo,.pl-vpf {
    color: #333;
}

.pl-ent {
    color: #63a35c;
}

.pl-k,.pl-s,.pl-st {
    color: #a71d5d;
}

.pl-pds,.pl-s1,.pl-s1 .pl-pse .pl-s2,.pl-sr,.pl-sr .pl-cce,.pl-sr .pl-sra,.pl-sr .pl-sre,.pl-src,.pl-v {
    color: #df5000;
}

.pl-id {
    color: #b52a1d;
}

.pl-ii {
    background-color: #b52a1d;
    color: #f8f8f8;
}

.pl-sr .pl-cce {
    color: #63a35c;
    font-weight: bold;
}

.pl-ml {
    color: #693a17;
}

.pl-mh,.pl-mh .pl-en,.pl-ms {
    color: #1d3e81;
    font-weight: bold;
}

.pl-mq {
    color: #008080;
}

.pl-mi {
    color: #333;
    font-style: italic;
}

.pl-mb {
    color: #333;
    font-weight: bold;
}

.pl-md,.pl-mdhf {
    background-color: #ffecec;
    color: #bd2c00;
}

.pl-mdht,.pl-mi1 {
    background-color: #eaffea;
    color: #55a532;
}

.pl-mdr {
    color: #795da3;
    font-weight: bold;
}

.pl-mo {
    color: #1d3e81;
}
.task-list {
padding-left:10px;
margin-bottom:0;
}

.task-list li {
    margin-left: 20px;
}

.task-list-item {
list-style-type:none;
padding-left:10px;
}

.task-list-item label {
font-weight:400;
}

.task-list-item.enabled label {
cursor:pointer;
}

.task-list-item+.task-list-item {
margin-top:3px;
}

.task-list-item-checkbox {
display:inline-block;
margin-left:-20px;
margin-right:3px;
vertical-align:1px;
}
</style>
<base target=_blank>
<meta http-equiv="X-UA-Compatible" content="IE=edge,Chrome=1">
<meta name="keywords" content="whjin,前端开发文档,html,css,javascript,canvas,jquery,vue.js,http,ajax,git,webpack">
<meta name="format-detection" content="telephone=no">
<meta name="description" content="前端开发文档">
<meta name="author" content="whjin">
<link rel="shortcut icon" href="https://i.imgur.com/vJ2LGVU.png">
</head>
<body>
<h1 id="react-">React基础</h1>
<h2 id="react-jsx">React-JSX</h2>
<p><strong>所谓的 <code>JSX</code> 其实就是 <code>JavaScript</code> 对象。</strong></p>
<p>从<code>JSX</code>到页面经历的过程：</p>
<p><img src="https://i.imgur.com/dBOd580.png" alt=""></p>
<p><strong>总结：</strong></p>
<ol>
<li><code>JSX</code> 是 <code>JavaScript</code> 语言的一种语法扩展；</li><li><code>React.js</code> 可以用 <code>JSX</code> 来描述你的组件；</li><li><code>JSX</code> 在编译的时候会变成相应的 <code>JavaScript</code> 对象描述；</li><li><code>react-dom</code> 负责把这个用来描述 <code>UI</code> 信息的 <code>JavaScript</code> 对象变成 <code>DOM</code> 元素，并且渲染到页面上。</li></ol>
<h2 id="-render-">组件的 <code>render</code> 方法</h2>
<p>一个组件类必须要实现一个 <code>render</code> 方法，这个 <code>render</code> 方法必须要返回一个 <code>JSX</code> 元素。必须要用一个外层的 <code>JSX</code> 元素把所有内容包裹起来，返回并列多个 <code>JSX</code> 元素是不合法的。</p>
<p><strong>表达式插入</strong></p>
<p>在 <code>JSX</code> 当中你可以插入 <code>JavaScript</code> 的表达式，表达式返回的结果会相应地渲染到页面上。表达式用 <code>{}</code> 包裹。</p>
<p><code>{}</code> 内可以放任何 <code>JavaScript</code> 的代码，包括<strong>变量</strong>、<strong>表达式计算</strong>、<strong>函数执行</strong>等。</p>
<p>表达式插入不仅仅可以用在标签内部，也可以用在标签的属性上。</p>
<p><strong>条件返回</strong></p>
<p>可以在 <code>render</code> 函数内部根据不同条件返回不同的 <code>JSX</code>。</p>
<p><strong><code>JSX</code> 元素变量</strong></p>
<h2 id="-">组件的组合、嵌套和组件树</h2>
<p><strong>自定义的组件都必须要用大写字母开头，普通的 <code>HTML</code> 标签都用小写字母开头。</strong></p>
<h2 id="-">事件监听</h2>
<p>在 <code>React.js</code> 不需要手动调用浏览器原生的 <code>addEventListener</code> 进行事件监听。<code>React.js</code> 帮我们封装好了一系列的 <code>on*</code> 的属性，当你需要为某个元素监听某个事件的时候，只需要简单地给它加上 <code>on*</code> 就可以了。而且你不需要考虑不同浏览器兼容性的问题，<code>React.js</code> 都帮我们封装好这些细节了。</p>
<p>这些事件属性名都必须要用驼峰命名法。</p>
<p>没有经过特殊处理的话，<strong>这些 <code>on*</code> 的事件监听只能用在普通的 <code>HTML</code> 的标签上，而不能用在组件标签上</strong>。</p>
<p><strong><code>event</code> 对象</strong></p>
<p><code>React.js</code> 中的 <code>event</code> 对象并不是浏览器提供的，而是它自己内部所构建的。<code>React.js</code> 将浏览器原生的 <code>event</code> 对象封装了一下，对外提供统一的 <code>API</code> 和属性，这样你就不用考虑不同浏览器的兼容性问题。</p>
<p><strong>关于事件中的 <code>this</code></strong></p>
<pre><code>handleClickOnTitle (e) {
    console.log(this) // =&gt; null or undefined
}
</code></pre><p>上面的 <code>handleClickOnTitle</code> 中把 <code>this</code> 打印出来，你会看到 <code>this</code> 是 <code>null</code> 或者 <code>undefined</code>。</p>
<p>这是因为 <code>React.js</code> 调用你所传给它的方法的时候，并不是通过对象方法的方式调用（<code>this.handleClickOnTitle</code>），而是直接通过函数调用 （<code>handleClickOnTitle</code>），所以事件监听函数内并不能通过 <code>this</code> 获取到实例。    </p>
<p>如果你想在事件函数当中使用当前的实例，你需要手动地将实例方法 <code>bind</code> 到当前实例上再传入给 <code>React.js</code>。</p>
<p><code>bind</code> 会把实例方法绑定到当前实例上，然后我们再把绑定后的函数传给 <code>React.js</code> 的 <code>onClick</code> 事件监听。</p>
<p>你也可以在 <code>bind</code> 的时候给事件监听函数传入一些参数。</p>
<p>这种 <code>bind</code> 模式在 <code>React.js</code> 的事件监听当中非常常见，<code>bind</code> 不仅可以帮我们把事件监听方法中的 <code>this</code> 绑定到当前组件实例上；还可以帮助我们在在渲染列表元素的时候，把列表元素传入事件监听函数当中。</p>
<h2 id="-state-setstate-">组件的 <code>state</code> 和 <code>setState</code></h2>
<p><strong>state</strong></p>
<p>一个组件的显示形态是可以由它数据状态和配置参数决定的。</p>
<p><strong><code>setState</code> 接受对象参数</strong></p>
<p><code>setState</code> 方法由父类 <code>Component</code> 所提供。<strong>当我们调用这个函数的时候，<code>React.js</code> 会更新组件的状态 <code>state</code> ，并且重新调用 <code>render</code> 方法，然后再把 <code>render</code> 方法所渲染的最新的内容显示到页面上</strong>。</p>
<p>当我们要改变组件的状态的时候，不能直接用 <code>this.state = xxx</code> 这种方式来修改，如果这样做 <code>React.js</code> 就没办法知道你修改了组件的状态，它也就没有办法更新页面。所以，一定要使用 <code>React.js</code> 提供的 <code>setState</code> 方法，它接受一个对象或者函数作为参数。</p>
<p><strong><code>setState</code> 接受函数参数</strong></p>
<p>当你调用 <code>setState</code> 的时候，<strong><code>React.js</code> 并不会马上修改 <code>state</code></strong>。而是把这个对象放到一个更新队列里面，稍后才会从队列当中把新的状态提取出来合并到 <code>state</code> 当中，然后再触发组件更新。</p>
<p><code>setState</code> 的第二种使用方式，可以接受一个函数作为参数。<code>React.js</code> 会把上一个 <code>setState</code> 的结果传入这个函数，你就可以使用该结果进行运算、操作，然后返回一个对象作为更新 <code>state</code> 的对象：</p>
<p><strong><code>setState</code> 合并</strong></p>
<p>上面我们进行了三次 <code>setState</code>，但是实际上组件只会重新渲染一次，而不是三次；这是因为在 <code>React.js</code> 内部会把 <code>JavaScript</code> 事件循环中的消息队列的同一个消息中的 <code>setState</code> 都进行合并以后再重新渲染组件。</p>
<p>在使用 <code>React.js</code> 的时候，并不需要担心多次进行 <code>setState</code> 会带来性能问题。</p>
<h2 id="-props-">配置组件的 <code>props</code></h2>
<p>如何让组件能适应不同场景下的需求，我们就要让组件具有一定的“<strong>可配置</strong>”性。</p>
<p><code>React.js</code> 的 <code>props</code> 就可以帮助我们达到这个效果。每个组件都可以接受一个 <code>props</code> 参数，它是一个对象，包含了所有你对这个组件的配置。</p>
<p>从 <code>render</code> 函数可以看出来，组件内部是通过 <code>this.props</code> 的方式获取到组件的参数的，如果 <code>this.props</code> 里面有需要的属性我们就采用相应的属性，没有的话就用默认的属性。</p>
<p><strong>在使用一个组件的时候，可以把参数放在标签的属性当中，所有的属性都会作为 <code>props</code> 对象的键值：</strong></p>
<p><strong>默认配置 <code>defaultProps</code></strong></p>
<p>上面的组件默认配置我们是通过 <code>||</code> 操作符来实现。这种需要默认配置的情况在 <code>React.js</code> 中非常常见，所以 <code>React.js</code> 也提供了一种方式 <code>defaultProps</code>，可以方便的做到默认配置。 </p>
<p><code>defaultProps</code> 作为点赞按钮组件的类属性，里面是对 <code>props</code> 中各个属性的默认配置。这样我们就不需要判断配置属性是否传进来了：如果没有传进来，会直接使用 <code>defaultProps</code> 中的默认属性。 所以可以看到，在 <code>render</code> 函数中，我们会直接使用 <code>this.props</code> 而不需要再做判断。</p>
<p><strong><code>props</code> 不可变</strong></p>
<p><code>props</code> 一旦传入进来就不能改变。</p>
<p>组件的使用者可以主动地通过重新渲染的方式把新的 <code>props</code> 传入组件当中，这样这个组件中由 <code>props</code> 决定的显示形态也会得到相应的改变。</p>
<p>我们把 <code>Index</code> 的 <code>state</code> 中的 <code>likedText</code> 和 <code>unlikedText</code> 传给 <code>LikeButton</code> 。<code>Index</code> 还有另外一个按钮，点击这个按钮会通过 <code>setState</code> 修改 <code>Index</code> 的 <code>state</code> 中的两个属性。</p>
<p>由于 <code>setState</code> 会导致 <code>Index</code> 重新渲染，所以 <code>LikedButton</code> 会接收到新的 <code>props</code>，并且重新渲染，于是它的显示形态也会得到更新。这就是通过重新渲染的方式来传入新的 <code>props</code> 从而达到修改 <code>LikedButton</code> 显示形态的效果。</p>
<p><strong>总结</strong></p>
<ol>
<li>为了使得组件的可定制性更强，在使用组件的时候，可以在标签上加属性来传入配置参数。</li><li>组件可以在内部通过 <code>this.props</code> 获取到配置参数，组件可以根据 <code>props</code> 的不同来确定自己的显示形态，达到可配置的效果。</li><li>可以通过给组件添加类属性 <code>defaultProps</code> 来配置默认参数。</li><li><code>props</code> 一旦传入，你就不可以在组件内部对它进行修改。但是你可以通过父组件主动重新渲染的方式来传入新的 <code>props</code>，从而达到更新的效果。</li></ol>
<h2 id="-state-vs-props-"><code>state</code> vs <code>props</code></h2>
<p><code>state</code> 的主要作用是用于组件保存、控制、修改自己的可变状态。<code>state</code> 在组件内部初始化，可以被组件自身修改，而外部不能访问也不能修改。你可以认为 <code>state</code> 是一个局部的、只能被组件自身控制的数据源。<code>state</code> 中状态可以通过 <code>this.setState</code> 方法进行更新，<code>setState</code> 会导致组件的重新渲染。</p>
<p><code>props</code> 的主要作用是让使用该组件的父组件可以传入参数来配置该组件。它是外部传进来的配置参数，组件内部无法控制也无法修改。除非外部组件主动传入新的 <code>props</code>，否则组件的 <code>props</code> 永远保持不变。</p>
<p><code>state</code> 和 <code>props</code> 有着千丝万缕的关系。它们都可以决定组件的行为和显示形态。一个组件的 <code>state</code> 中的数据可以通过 <code>props</code> 传给子组件，一个组件可以使用外部传入的 <code>props</code> 来初始化自己的 <code>state</code>。但是它们的职责其实非常明晰分明：<code>state</code> 是让组件控制自己的状态，<code>props</code> 是让外部对组件自己进行配置。</p>
<p><strong>尽量少地用 <code>state</code>，尽量多地用 <code>props</code>。</strong></p>
<p>没有 <code>state</code> 的组件叫无状态组件，设置了 <code>state</code> 的叫做有状态组件。因为状态会带来管理的复杂性，我们尽量多地写无状态组件，尽量少地写有状态的组件。这样会降低代码维护的难度，也会在一定程度上增强组件的可复用性。</p>
<p><code>React.js</code> 非常鼓励无状态组件，在 <code>0.14</code> 版本引入了函数式组件——一种定义不能使用 <code>state</code> 组件。</p>
<blockquote>
<p>以前一个组件是通过继承 <code>Component</code> 来构建，一个子类就是一个组件。而用函数式的组件编写方式是一个函数就是一个组件，你可以和以前一样通过 <code>&lt;HellWorld /&gt;</code> 使用该组件。不同的是，函数式组件只能接受 <code>props</code> 而无法像跟类组件一样可以在 <code>constructor</code> 里面初始化 <code>state</code>。你可以理解函数式组件就是一种只能接受 <code>props</code> 和提供 <code>render</code> 方法的类组件。</p>
</blockquote>
<pre><code>const users = [
  { username: &#39;Jerry&#39;, age: 21, gender: &#39;male&#39; },
  { username: &#39;Tomy&#39;, age: 22, gender: &#39;male&#39; },
  { username: &#39;Lily&#39;, age: 19, gender: &#39;female&#39; },
  { username: &#39;Lucy&#39;, age: 20, gender: &#39;female&#39; }
]
</code></pre>
</body>
</html>
<!-- This document was created with MarkdownPad, the Markdown editor for Windows (http://markdownpad.com) -->
